package com.bizfx.component.fields
{
	import flash.events.Event;
	import flash.events.FocusEvent;
	
	import com.bizfx.component.FieldDataType;
	import com.bizfx.component.views.IDetailView;
	import com.bizfx.utils.DateUtils;
	import com.bizfx.utils.ObjectUtils;
	import com.bizfx.utils.StringUtils;
	
	import mx.collections.ArrayCollection;
	import mx.collections.IList;
	import mx.containers.Canvas;
	import mx.controls.DateField;
	import mx.controls.TextArea;
	import mx.events.FlexEvent;
	import mx.events.ValidationResultEvent;
	import mx.formatters.DateFormatter;
	import mx.utils.UIDUtil;
	import mx.validators.StringValidator;
	
	public class TextAreaField extends Canvas implements IField, IValidationField
	{
		private var dateFormatter:DateFormatter = new DateFormatter();
		
		private var input:TextArea = new TextArea();
		
		private var _validator:StringValidator = new StringValidator();
		
		private var sizeDirty:Boolean = true;
		
		private var requiredDirty:Boolean = true;
		
		private var dataDirty:Boolean = false;
		
		private var textDirty:Boolean = false;
		
		private var dataTypeDirty:Boolean = true;
		
		private var dateFormatString:String = "YYYY-MM-DD";
		
		private var dateTimeFormatString:String = "YYYY-MM-DD HH:NN:SS";
		
		private var aDataType:String = FieldDataType.STRING;
		
		public function TextAreaField() {
			super();
			this.addEventListener("widthChanged", widthChangedHandler);
			this.addEventListener("heightChanged", heightChangedHandler);
			this.input.addEventListener(Event.CHANGE, fieldChangeHandler);
			this.input.addEventListener(FocusEvent.FOCUS_OUT, fieldFocusOutHandler);
		}
		
		override protected function createChildren():void {
			super.createChildren();
			if (this.width <= 0 && (isNaN(this.percentWidth) || this.percentWidth <= 0)) {
				this.width = 300;
			}
			if (this.height <= 0 && (isNaN(this.percentHeight) || this.percentHeight <= 0)) {
				this.height = 50;
			}
			this.input.percentHeight = 100;
			this.input.percentWidth = 100;
			this._validator.required = false;
			this._validator.requiredFieldError = "必填";
			this.input.setStyle("backgroundDisabledColor", 0xFFFFFF);
			this.input.setStyle("disabledOverlayAlpha", 0);
			this.input.setStyle("disabledColor", 0x000000);
			this.setStyle("backgroundDisabledColor", 0xFFFFFF);
			this.setStyle("disabledOverlayAlpha", 0);
			this.setStyle("disabledColor", 0x000000);
			this.addChild(this.input);
		}
		
		private function fieldChangeHandler(event:Event):void {
			this.textDirty = true;
		}
		
		private function fieldFocusOutHandler(event:FocusEvent):void {
			if (this.textDirty) {
				this.input.text = this.defaultDisplayFunction(this.input.text);
				this.invalidateProperties();	
			}
		}
		
		[Bindable]
		public function get fieldKey():String
		{
			return this.id;
		}
		
		public function set fieldKey(value:String):void
		{
			id = value;
		}
		
		private var _bindProperty:String;
		[Bindable]
		public function get bindProperty():String {
			return _bindProperty;
		}
		
		public function set bindProperty(value:String):void {
			_bindProperty = value;
		}
		
		private var _displayProperty:String;
		[Bindable]
		public function get displayProperty():String
		{
			return _displayProperty;
		}
		
		public function set displayProperty(value:String):void {
			_displayProperty = value;
		}
		
		private var _required:Boolean;
		[Bindable]
		public function get required():Boolean {
			return this._required;
		}
		
		public function set required(value:Boolean):void {
			if (this._required != value) {
				this._required = value;
				this.requiredDirty = true;
				this.invalidateDisplayList();
			}
		}
		
		[Bindable]
		public function get restrict():String {
			return this.input.restrict;
		}
		
		public function set restrict(value:String):void {
			this.input.restrict = value;
		}
		
		[Bindable("dataChange")]
		[Inspectable(category="General")]
		override public function get data():Object {
			if (this.input.data == null) {
				return null;
			} else if (StringUtils.isNullOrEmpty(this.input.data.toString())) {
				return null;
			} else {
				return this.input.data;
			}
		}
		
		override public function set data(value:Object):void {
			if (this.input.data != value) {
				this.dataDirty = true;
				
				if (this.input.data is IEventDispatcher) {
					ObjectProxy(this.input.data).removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, valuePropertyChangeHandler);
				}
				
				if (value is ObjectProxy 
					|| value is String 
					|| value is Date 
					|| value is Number
					|| value is Boolean
					|| value is int
					|| value is uint
					|| value == null) {
					this.input.data = value;
				} else {
					this.input.data = value?new ObjectProxy(value): null;
				}
				if (!StringUtils.isNullOrEmpty(this.displayProperty) && this.input.data is IEventDispatcher) {
					ObjectProxy(this.input.data).addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, valuePropertyChangeHandler);
				}
				this.dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
				this.invalidateDisplayList();
			}
		}
		
//		private var _view:IDetailView;
//		
//		public function get view():IDetailView
//		{
//			return this._view;
//		}
//		
//		public function set view(value:IDetailView):void {
//			if (StringUtils.isNullOrEmpty(this.id)) {
//				this.id = UIDUtil.createUID();
//			}
//			if (this._view !== value) {
//				if (_view) {
//					_view.removeFieldByKey(this.fieldKey);
//				}
//				this._view = value;
//				if (_view) {
//					_view.addField(this);
//				}
//			}
//		}
		
		private var _editable:Boolean = true;
		[Bindable]
		[Inspectable(category="General", enumeration="true,false", defaultValue="true")]
		public function get editable():Boolean
		{
			return this._editable;
		}
		
		public function set editable(value:Boolean):void {
			this._editable = value;
			if (!this._editable) {
				this.input.editable = false;
			}
		}
		
		private var _enabled:Boolean = true;
		[Bindable]
		[Inspectable(category="General", enumeration="true,false", defaultValue="true")]
		override public function get enabled():Boolean
		{
			return this._enabled;
		}
		
		override public function set enabled(value:Boolean):void {
			this._enabled = value;
			if (this.editable) {
				this.input.editable = value;
			} else {
				this.input.editable = false;
			}
		}
		
		[Bindable]
		[Inspectable(category="General")]
		public function get displayAsPassword():Boolean {
			return this.input.displayAsPassword;
		}
		
		public function set displayAsPassword(value:Boolean):void {
			this.input.displayAsPassword = value;
		}
		
		private var _displayFunction:Function;
		
		public function get displayFunction():Function
		{
			return _displayFunction;
		}
		
		public function set displayFunction(value:Function):void
		{
			_displayFunction = value;
		}
		
		private var _dataType:String = "Auto";
		[Bindable]
		[Inspectable(category="General", enumeration="Boolean,String,Integer,Float,Date,DateTime,Auto", defaultValue="String")]
		public function get dataType():String
		{
			return _dataType;
		}
		
		public function set dataType(value:String):void
		{
			if (this._dataType != value) {
				_dataType = value;
				this.dataTypeDirty = true;
				this.invalidateDisplayList();
			}
		}
		
		[Inspectable(category="General", enumeration="true,false", defaultValue="false")]
		[Bindable("readOnlyChanged")]
		public function get readOnly():Boolean {
			return this.enabled;
		}
		
		public function set readOnly(value:Boolean):void {
			if (this.enabled == value) {
				this.enabled = !value;
				this.dispatchEvent(new Event("readOnlyChanged"));
			}
		}
		
		private var _validators:IList;
		
		public function get validators():IList
		{
			if (this._validators == null) {
				this._validators = new ArrayCollection();
			}
			return _validators;
		}
		
		public function set validators(value:IList):void
		{
			_validators = value;
		}
		
		public function validate():void {
			this._validator.source = this.input;
			this._validator.property = "text";
			var event:ValidationResultEvent = this._validator.validate(this.input.text);
			this.dispatchEvent(event);
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			if (this.sizeDirty) {
				this.sizeDirty = false;
				this.input.width = this.width;
				this.input.height = this.height;
			}
			
			if (this.requiredDirty) {
				this.requiredDirty = false;
				this._validator.required = this.required;
			}
			
			var i:int = this.input.selectionEndIndex;
			if (this.dataDirty) {
				this.dataDirty = false;
				if (this.input.data) {
					if (!StringUtils.isNullOrEmpty(this.displayProperty)) {
						if (this.data.hasOwnProperty(this.displayProperty)) {
							this.input.text = this.defaultDisplayFunction(ObjectUtils.getPropertyValue(this.input.data, this.displayProperty));
							this.input.setSelection(i, i);
						}
					} else {
						this.input.text = this.defaultDisplayFunction(this.input.data);
						this.input.setSelection(i, i);
					}
				} else {
					this.input.text = defaultDisplayFunction(this.input.data);
					this.input.setSelection(i, i);
				}
			}
			
			if (this.dataTypeDirty) {
				this.dataTypeDirty = false;
				if (this.dataType == "Auto") {
					var d:Object = ObjectUtils.getPropertyValue(this.input.data, this.displayProperty);
					if (d is String) {
						this.aDataType = FieldDataType.STRING
					} else if (d is Number) {
						this.aDataType = FieldDataType.FLOAT;
					} else if (d is Date) {
						this.aDataType = FieldDataType.DATETIME;
					}
				}
				
				switch (this.aDataType) {
					case FieldDataType.INTEGER:
						this.input.restrict = "-?\0-9"
						break;
					case FieldDataType.FLOAT:
						this.input.restrict = "-?\0-9\."
						break;
					case FieldDataType.DATE:
						this.input.restrict = "0-9\-"
					case FieldDataType.DATETIME:
						this.input.restrict = "0-9\-\:\ "
					default:
						this.input.restrict = null;
						break;
				}
			}
		}
		
		override protected function commitProperties():void {
			super.commitProperties()
			if (this.textDirty) {
				this.textDirty = false;
				var newData:Object = null;
				switch (this.aDataType) {
					case FieldDataType.DATE: 
						newData = DateField.stringToDate(this.input.text, this.dateFormatString);
						break;
					case FieldDataType.DATETIME:
						newData = DateUtils.StringToDate(this.input.text);
						break;
					case FieldDataType.FLOAT:
						if (StringUtils.isNullOrEmpty(this.input.text)) {
							newData = null;
						} else {
							newData = new Number(this.input.text);
						}
						break;
					case FieldDataType.FLOAT:
						if (StringUtils.isNullOrEmpty(this.input.text)) {
							newData = null;
						} else {
							newData = int(this.input.text);
						}
						break;
					default:
						newData = this.input.text;
						
				}
				if (!StringUtils.isNullOrEmpty(this.displayProperty)) {
					ObjectUtils.setPropertyValue(this.input.data, this.displayProperty, newData);
				} else {
					this.input.data = newData;
				}
			}
		}
		
		protected function valuePropertyChangeHandler(event:PropertyChangeEvent):void {
			if (!StringUtils.isNullOrEmpty(this.displayProperty) 
				&& event.property == this.displayProperty) {
				this.dataDirty = true;
				this.invalidateDisplayList();
			}
		}
		
		private function widthChangedHandler(event:Event):void {
			this.sizeDirty = true;
			this.invalidateDisplayList();
		}
		
		private function heightChangedHandler(event:Event):void {
			this.sizeDirty = true;
			this.invalidateDisplayList();
		}
		
		private function defaultDisplayFunction(value:Object):String {
			if (value) {
				switch (this.dataType) {
					case FieldDataType.BOOLEAN:
						return value?"是":"否";
					case FieldDataType.DATE:
						try {
							if (value.valueOf() == new Date(0, 0, 0).valueOf()) {
								return "";
							} else {
								dateFormatter.formatString="YYYY-MM-DD";
								return dateFormatter.format(value);						
							}
						} catch(err:Error) {
							return "";
						}
					case FieldDataType.DATETIME:
						try {
							if (value.valueOf() == new Date(0, 0, 0).valueOf()) {
								return "";
							} else {
								dateFormatter.formatString="YYYY-MM-DD HH:NN:SS";
								return dateFormatter.format(value);						
							}
						} catch (err:Error) {
							return "";
						}
					default:
						return value.toString();
				}	
			} else {
				return "";
			}
		}
	}
}